<?php

/**
 * MySQL数据库连接类
 * The class of Mysql Opreation
 */

include_once (_CONST_LOCAL_INCLUDE_PATH."mcached.class.php");

class Database {

  # 运行模式
  # running mode
  public $debug_mode = false;
  # 查询次数
  # query times
  private $query_count = 0;
  # 保存debug信息的数组
  # The Array for saving debug information
  private $debug_array = array();

  # 数据库名
  # Database Name
  private $database = null;
  # 登录名
  # DB Login Name
  private $username = null;
  # 登录密码
  # DB PassWord
  private $password = null;
  # 数据库ip
  # DB IP Address or Domain Name
  private $hostname = null;
  # 连接串
  # Connection Resource
  private $conn = null;
  # 影响条数
  # affected rows
  private $affected_rows = 0;
  # result
  private $result = null;
  # auto insert ID
  private $insert_id = 0;
  # number of rows
  private $num_rows = 0;
  # current row
  private $cur_row = 0;

	private function throw_error($message) {
		throw new Exception($message);
	}

  /**
   * 构造函数 在类被装载时就直接连接mysql
   * const function Content to Mysql DB when the class been Loaded.
   * @param $db_vars  数据库链接数组
   *   $db_vars = array(
   *     'hostname' => 'localhost',
   *     'database' => 'test',
   *     'username' => 'root',
   *     'password' => 'jasmine',
   *   );
   * @param $is_persistent  是否采用持久链接，0为默认方式链接；1为持久链接
   */
  function __construct($db_vars, $is_persistent = 0) {
    # 给变量赋值
    if (!is_array($db_vars)) {
      $this->throw_error("<b>MySQL Error </b>: No db_vars found.");
    }
    $this->database = $db_vars['database'];
    $this->username = $db_vars['username'];
    $this->password = $db_vars['password'];
    $this->hostname = $db_vars['hostname'];

    # 连接数据库
    if ($is_persistent == 1) {
      # 持久链接
      $this->conn = @mysql_pconnect(
        $this->hostname,
        $this->username,
        $this->password
      ) or $this->throw_error("<b>MySQL Error (".@mysql_errno().")</b>: ".@mysql_error().".");
    } else {
      # 普通链接
      $this->conn = @mysql_connect(
        $this->hostname,
        $this->username,
        $this->password
      ) or $this->throw_error("<b>MySQL Error (".@mysql_errno().")</b>: ".@mysql_error().".");
    }

    # 选择数据库
    mysql_select_db($this->database, $this->conn)
      or $this->throw_error("<b>MySQL Error (".@mysql_errno().")</b>: ".@mysql_error().".");
        #中文乱码
    mysql_query("SET NAMES UTF8");
  }

  /**
   * 析构函数
   *
   *
   */
  function __destruct() {
    $this->freeResult();
    @mysql_close($this->conn);
    # debug
    if ($this->debug_mode) {
      $this->displayDebug();
    }
  }

  /**
   * 通用select查询
   *
   * @param String $sql
   * @return
   *    Die when this query with error
   *    or
   *      Array   the query result by array
   * @access pubilc
   */
  public function queryArray($sql, $expires = 0) {
    if ($expires > 0 && _MEMCACHED) {
      $cache_name = md5($sql);

      if ($_data = Mcache::get($cache_name)) {
      } else {
        # 执行
        $this->execute($sql);

        # 获取数据
        # get data
        $count = 0;
        $_data = array();
        while ($row = mysql_fetch_array($this->result, MYSQL_ASSOC)) {
          $_data[$count] = $row;
          $count++;
        }

        Mcache::set($cache_name, $_data, $expires);

        # 消除结果资源
        # distory resource
        $this->freeResult();
      }
    } else {
      # 执行
      $this->execute($sql);

      # 获取数据
      # get data
      $count = 0;
      $_data = array();
      while ($row = mysql_fetch_array($this->result, MYSQL_ASSOC)) {
        $_data[$count] = $row;
        $count++;
      }

      # 消除结果资源
      # distory resource
      $this->freeResult();
    }

    # return Array
    return $_data;
  }

  /*
   * 返回select的第一条
   */
  public function queryFirst($sql, $expires = 0) {
    if ($expires > 0 && _MEMCACHED) {
      $cache_name = md5($sql);
      $mcache = new Mcache();
      if ($row = $mcache->get($cache_name)) {
      } else {
        # 执行
        $this->execute($sql);

        # 获取数据
        # get data
        $row = mysql_fetch_array($this->result, MYSQL_ASSOC);

        $mcache->set($cache_name, $row, $expires);

        # 消除结果资源
        # distory resource
        $this->freeResult();
      }
    } else {
      # 执行
      $this->execute($sql);

      # 获取数据
      # get data
      $row = mysql_fetch_array($this->result, MYSQL_ASSOC);

      # 消除结果资源
      # distory resource
      $this->freeResult();
    }

    return $row;
  }

  /**
   * 执行
   * @param $sql
   * @return  true
   *      OR
   *      false
   * @access public
   */
  public function execute($sql) {
    # debug
    if ($this->debug_mode) {
      $_time_start = $this->getMicrotime();
    }

    # execute
    $this->result = @mysql_query($sql, $this->conn)
      or $this->throw_error("<b>MySQL Error (".@mysql_errno().")</b>: ".@mysql_error().".<br><b>SQL:</b> $sql");


    if ($this->result) {
      # 影响条数
      $this->affected_rows = @mysql_affected_rows($this->conn);
      # 自增ID
      $this->insert_id = @mysql_insert_id($this->conn);
      # 获得的行数
      $this->num_rows = @mysql_num_rows($this->result);
      # 当前指针清零
      $this->cur_row = 0;

      # debug
      if ($this->debug_mode) {
        $_wash_time = $this->getMicrotime() - $_time_start;
        $this->setDebug($_wash_time.", ".$sql);
      }

      return true;
    } else {
      return false;
    }
  }

  /**
   * 从select后的结果中提取一行
   * @return Array
   * @access public
   */
  public function getRecord() {
    $this->cur_row++;
    return mysql_fetch_array($this->result, MYSQL_ASSOC);
  }

  /**
   * 在获取资源的时候判断是否到低
   * @return true OR false
   * @access public
   */
  public function ifEOF() {
    if ($this->cur_row >= $this->num_rows) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * 释放资源
   * @return void
   * @access public
   */
  public function freeResult() {
    @mysql_freeresult($this->result);
  }

  /**
   * 翻页select
   * page Select
   *
   * @param String $sql
   * @param Int $page
   * @param Int $length
   *    Die when this query with error
   *    or
   *      Array   the query result by array
   * @access public
   */
  public function queryPage($sql, $page = 1, $length = 100) {
    # 检查页数是否合法
    # check nums
    if (!is_numeric($page) or !is_numeric($length)) {
        $this->throw_error("<b>MySQL Error </b>: db page_query with not numeric parm..<br><b>SQL:</b> $sql");
        return false;
    }

    $real_sql = $sql." LIMIT ".($page - 1) * $length.", ".$length;
    $rs = $this->queryArray($real_sql);
    return $rs;
  }

  /**
   * 获得影响行数
   * get afficted rows
   *
   * @param null
   * @return Int afficted rows
   * @access pubilc
   */
  public function getAffectedRows() {
    return $this->affected_rows;
  }

  /**
   * 获得最后插入的ID号
   * 如果上一步操作有值，则返回 ID号码
   * 如果上一步操作没有值，则返回 0
   * @param void
   * @return
   *    int , if last step is insert, then return the number of insert auto_increment
   *    OR
   *    int 0, if there was no auto_increment value, then return 0.
   * @access public
   *
   */
  public function getInsertId() {
    return $this->insert_id;
  }

  /**
   * 返回结果资源给外部
   * @return $this->result
   * @access public
   */

  public function getResult() {
    return $this->result;
  }

  public function getNumRows() {
    return $this->num_rows;
  }

  /**
   * set debug
   * @param $string , debug string
   * @return void
   * @access private
   */
  private function setDebug($string) {
    $this->debug_array[$this->query_count] = $string;
    $this->query_count++;
  }

  /**
   * display debug
   * @param void
   * @return void
   * @access private
   */
  private function displayDebug() {
    $array = $this->debug_array;
    //echo "<!-- ";
    echo "<div style='background-color:yellow;font-size:12px;line-height:150%;padding:10px;text-align:left;'>";
    for($i = 0; $i < sizeof($array); $i++) {
      echo ($i + 1).", ".$array[$i]."<br>" ;
    }
    echo "</div>";
    //echo " -->";
  }

  private function getMicrotime()
  {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
  }
}
// End of Database Class